package com.zdp.middleware.methodext;

import com.alibaba.fastjson.JSON;
import com.sun.xml.internal.ws.developer.StreamingAttachment;
import com.zdp.middleware.methodext.annotation.DoMethodExt;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 * @author ZhengDp
 * @Date 2023/5/27 16:14
 */
@Aspect
@Component
public class DoMethodExtPoint {

    private Logger logger = LoggerFactory.getLogger(DoMethodExtPoint.class);

    @Pointcut("@annotation(com.zdp.middleware.methodext.annotation.DoMethodExt)")
    public void aopPoint(){}

    @Around("aopPoint() && @annotation(doMethodExt)")
    public Object doRouter(ProceedingJoinPoint jp, DoMethodExt doMethodExt) throws Throwable {
        Method method = getMethod(jp);

        // 获取拦截的方法
        String methodName = doMethodExt.method();
        Method methodExt = getClass(jp).getDeclaredMethod(methodName,method.getParameterTypes());
        methodExt.setAccessible(true);
        Class<?> returnType = methodExt.getReturnType();

        // 判断方法返回类型
        if(!returnType.getName().equals("boolean")) {
            throw new RuntimeException("annotation @DoMethodExt set method : " + methodName + " returnType is not boolean");
        }
        boolean invoke = (boolean) methodExt.invoke(jp.getThis(),jp.getArgs());
        return invoke ? jp.proceed() : JSON.parseObject(doMethodExt.returnJson(),method.getReturnType());
    }


    private Method getMethod(ProceedingJoinPoint jp) throws NoSuchMethodException {
        Signature signature = jp.getSignature();
        MethodSignature methodSignature = (MethodSignature) signature;
        return jp.getTarget().getClass().getMethod(methodSignature.getName(),methodSignature.getParameterTypes());
    }

    private Class<? extends Object> getClass(ProceedingJoinPoint jp) {
        return jp.getTarget().getClass();
    }
}
